package com.cy.utils;

import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;

/**
 * 简单的HTTP工具
 */
public final class SimpleHttpUtils {

    private SimpleHttpUtils() {}


    /**
     * 转换器
     * @param <S> 源类型
     * @param <T> 目标类型
     */
    public interface Convertor<S,T>{
        /**
         * 类型转换
         * @param source 源数据
         * @return 目标数据
         */
        T convert(S source, Object...extra);
    }

    /**
     * 发送HTTP请求
     * @param requestUrl 请求地址
     * @param method 请求方法，只支持POST/GET
     * @param responseCharset 响应数据编码
     * @param data 请求参数
     * @return 响应数据
     */
    public static String sendRequest(String requestUrl, String method, String responseCharset, Map<String, String[]> data) {
        return sendRequest(requestUrl, method, responseCharset, null, data);
    }

    /**
     * 发送HTTP请求
     * @param requestUrl 请求地址
     * @param method 请求方法，只支持POST/GET
     * @param data 请求参数
     * @param convertor 响应数据转换器
     * @return 响应数据
     */
    public static <T> T sendRequest(String requestUrl, String method, Map<String, String[]> data, Convertor<String, T> convertor){
        return sendRequest(requestUrl, method, System.getProperty("file.encoding"), data, convertor);
    }

    /**
     * 发送HTTP请求
     * @param requestUrl 请求地址
     * @param method 请求方法，只支持POST/GET
     * @param responseCharset 响应数据编码
     * @param data 请求参数
     * @param convertor 响应数据转换器
     * @return 响应数据
     */
    public static <T> T sendRequest(String requestUrl, String method, String responseCharset, Map<String, String[]> data, Convertor<String, T> convertor){
        if (convertor == null)
            throw new RuntimeException("convertor is null");
        return convertor.convert(sendRequest(requestUrl, method, responseCharset, null, data), requestUrl, data);
    }

    /**
     * 发送HTTP请求
     * @param requestUrl 请求地址
     * @param method 请求方法，只支持POST/GET
     * @param responseCharset 响应数据编码
     * @param requestBody 请求体
     * @param data 请求参数
     * @param convertor 响应数据转换器
     * @return 响应数据
     */
    public static <T> T sendRequest(String requestUrl, String method, String responseCharset, String requestBody, Map<String, String[]> data, Convertor<String, T> convertor){
        if (convertor == null)
            throw new RuntimeException("convertor is null");
        return convertor.convert(sendRequest(requestUrl, method, responseCharset, requestBody, data), requestUrl, data);
    }

    /**
     * 发送HTTP请求
     * @param requestUrl 请求地址
     * @param method 请求方法，只支持POST/GET
     * @param data 请求参数
     * @return 响应数据
     */
    public static String sendRequest(String requestUrl, String method, Map<String, String[]> data){
        return sendRequest(requestUrl, method, System.getProperty("file.encoding"), null, data);
    }

    /**
     * 发送HTTP请求
     * @param requestUrl 请求地址
     * @param method 请求方法，只支持POST/GET
     * @param responseCharset 响应数据编码
     * @param requestBody 请求体
     * @param data 请求参数
     * @return 响应数据
     */
    public static String sendRequest(String requestUrl, String method, String responseCharset, String requestBody, Map<String, String[]> data){
        BufferedReader br = null;
        DataOutputStream dos = null;
        StringBuilder paramUrl = new StringBuilder(requestUrl);
        try {
            if ("GET".equals(method = method.toUpperCase())){
                if (data != null){
                    paramUrl.append("?");
                    paramUrl.append(appendParam(data));
                }
            }
            URL url = new URL(paramUrl.toString());
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setConnectTimeout(10000);//10秒连接超时
            connection.setReadTimeout(10000);//10秒读超时
            connection.setDoInput(true);
            connection.setDoOutput(true);
            connection.setUseCaches(true);
            connection.setRequestMethod(method);

            boolean hasBody;
            if (hasBody = StringUtils.isNotBlank(requestBody)){
                try{
                    JSONObject.parse(requestBody);
                    connection.setRequestProperty("Content-Type", "application/json"); 
                } catch (Exception e){}
            }
            connection.connect();

            if ("POST".equals(method)){
                dos = new DataOutputStream(connection.getOutputStream());
                if (data != null){
                    dos.writeBytes(appendParam(data));
                }
                if (hasBody){
                    dos.writeBytes(requestBody);
                }
            }

            br = new BufferedReader(new InputStreamReader(connection.getInputStream(), responseCharset));
            StringBuilder result = new StringBuilder();
            String line;
            while((line = br.readLine()) != null){
                result.append(line);
            }
            return result.toString().trim();
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            try {
                if (br != null) br.close();
                if (dos != null) dos.close();
            } catch (IOException e) {}
        }
    }

    private static String appendParam(Map<String, String[]> data){
        StringBuilder params = new StringBuilder();
        for (Map.Entry<String, String[]> entry : data.entrySet()){
            for (String param : entry.getValue()){
                params.append(entry.getKey()).append("=").append(param).append("&");
            }
        }
        return params.substring(0, params.length() - 1);
    }

    /**
     * 获取真实IP
     *
     * @param request
     * @return
     */
    public static String getIpAdress(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
            ip = request.getHeader("Proxy-Client-IP");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
            ip = request.getHeader("WL-Proxy-Client-IP");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
            ip = request.getRemoteAddr();
        return ip;
    }

}
